//----------------------------------------------
//   线程池管理员
//   ThreadPoolMgr.h.
//   26/04/2021       by.mv
//----------------------------------------------
#pragma once

#ifndef _THREADPOOL_H
#define _THREADPOOL_H 

//----------------------------------------------
// headers.
//----------------------------------------------
#include <vector> 
#include <queue> 
#include <memory>
#include <thread> 
#include <mutex> 
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>

//----------------------------------------------
namespace mv
{
	//----------------------------------------------
	class ThreadPool
	{
	public:
		//------------------------------------------------
		//           提交任务
		//-------------------------------------------------
        ThreadPool(size_t); 
		template<class F, class... Args>
		auto enqueue(F&& f, Args&&... args)->std::future<typename std::result_of<F(Args...)>::type>;
        ~ThreadPool();

	private:
		// need to keep track of threads so we can join them 】
		// 线程池
		std::vector< std::thread > m_CWorkers;
		// the task queue 
		//声明 任务队列 放函数指针
		std::queue< std::function<void()> > m_CTasks;
		// synchronization 
		// 互斥锁 与 条件锁 与 任务停止指令
		std::mutex m_mxQueue;
		std::condition_variable m_CCondition;
		bool m_bStop = false;	
	};
	//----------------------------------------------
}
 
 // the constructor just launches some amount of workers
 // 注意 第一次使用线程池需要初始化 创建子线程需要时间开销
 inline mv::ThreadPool::ThreadPool(size_t threads)
 { 
	 for(size_t i = 0 ;i< threads/*std::thread::hardware_concurrency()*/;++i)
		 m_CWorkers.emplace_back( [this] {
		 for (;;) {
			 std::function<void()> m_pTask;
			 {
				 std::unique_lock<std::mutex> lock(this->m_mxQueue);
				 this->m_CCondition.wait(lock, [this] { return this->m_bStop || !this->m_CTasks.empty(); });

				 if (this->m_bStop && this->m_CTasks.empty())
					 return;

				 m_pTask = std::move(this->m_CTasks.front());
				 this->m_CTasks.pop();
			 }
			 m_pTask();//执行任务
		 }
	 } );
 }
 //内联模板函数 参数 函数指针 ， 右值引用 拖尾返回类型
 // add new work item to the pool 
 template<class F, class... Args> 
 inline auto mv::ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>
 { 
	 //重命名函数指针类型
	 using return_type = typename std::result_of<F(Args...)>::type; 
	 //打包任务task
	 auto m_task = std::make_shared< std::packaged_task<return_type()> >( std::bind(std::forward<F>(f), std::forward<Args>(args)...) );
	 //创建期望
	 std::future<return_type> res_future = m_task->get_future();
	
	 //上独占锁
	 { 
		 std::unique_lock<std::mutex> m_lock(m_mxQueue);
		 // don't allow enqueueing after stopping the pool
		 if (m_bStop)
			 throw std::runtime_error("enqueue on stopped ThreadPool");

		 m_CTasks.emplace([m_task]() {
			 (*m_task)(); });
	 }
	 m_CCondition.notify_one();
	 //通知 消费者(workerThread) 
	 return res_future;
 }
 // the destructor joins all threads
 inline mv::ThreadPool::~ThreadPool() {
	 {
		std::unique_lock<std::mutex> m_lock(m_mxQueue);
		m_bStop = true;
	 }

	 m_CCondition.notify_all();
	 for(std::thread &m_CWorker: m_CWorkers)
		 m_CWorker.join();
 }

#endif //!_THREADPOOL_H